package com.example.javaproject.design;

/**
 * 工厂方法模式
 *
 * ![参考文档](https://www.zhihu.com/question/27125796/answer/1615074467)
 *
 * 简单工厂：唯一工厂类，一个产品抽象类，工厂类的创建方法依据入参判断并创建具体产品对象。
 * 工厂方法：多个工厂类，一个产品抽象类，利用多态创建不同的产品对象，避免了大量的if-else判断。
 * 抽象工厂：多个工厂类，多个产品抽象类，产品子类分组，同一个工厂实现类创建同组中的不同产品，减少了工厂子类的数量
 */
public class FactoryPattern {

    public static void main(String[] args) {
        // 1、测试工厂方法
        Factory factory = new ConcreteFactory();
        Product product = factory.createProduct();
        product.method();

        // 2、在1中的问题是需要创建的产品是固定的，我们稍微改写一下
        BaseFactory factory1 = new NormalFactory();
        Product product1 = factory1.createProduct(ConcreteProductB.class);
        product1.method();

        // 3、在2中使用的反射动态生成产品，3的实现是每个具体产品有具体的工厂, 这就是"多工厂方法模式"
        Factory fa = new FactoryA();
        Product pa = fa.createProduct();
        pa.method();

        Factory fb = new FactoryB();
        Product pb = fb.createProduct();
        pb.method();

        // 4、当只有一个工厂时，我们称为"简单工厂模式"，这是可以省去工厂接口的定义
        Product pa1 = SimpleFactory.createProduct(ConcreteProductA.class);
        pa1.method();
        Product pb1 = SimpleFactory.createProduct(ConcreteProductB.class);
        pb1.method();

        // 5、抽象工厂
        CarFactory q3Factory = new Q3Factory();
        q3Factory.createCarEngine().engine();
        q3Factory.createCarTire().tire();

        CarFactory q5Factory = new Q5Factory();
        q5Factory.createCarEngine().engine();
        q5Factory.createCarTire().tire();
    }
}


abstract class Product {
    public abstract void method();
}

class ConcreteProductA extends Product {
    @Override
    public void method() {
        System.out.println("我是具体产品A");
    }
}

class ConcreteProductB extends Product {
    @Override
    public void method() {
        System.out.println("我是具体产品B");
    }
}


interface Factory {
    Product createProduct();
}

class ConcreteFactory implements Factory {
    @Override
    public Product createProduct() {
        return new ConcreteProductA();
    }
}

interface BaseFactory {
    Product createProduct(Class cls);
}

class NormalFactory implements BaseFactory {

    @Override
    public Product createProduct(Class cls) {
        Product p = null;
        try {
            p = (Product) Class.forName(cls.getName()).getDeclaredConstructor().newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return p;
    }
}

class FactoryA implements Factory {

    @Override
    public Product createProduct() {
        return new ConcreteProductA();
    }
}

class FactoryB implements Factory {

    @Override
    public Product createProduct() {
        return new ConcreteProductB();
    }
}

/**
 * 简单工厂模式不必定义接口
 */
class SimpleFactory {
    public static Product createProduct(Class cls) {
        Product p = null;
        try {
            p = (Product) Class.forName(cls.getName()).getDeclaredConstructor().newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return p;
    }
}

/// 抽象工厂例子，这里以工厂生产q3，与q7与例子,他们的发动机和轮胎不一样

/**
 * 抽象工厂类
 */
interface CarFactory {
    /**
     * 生产发动机
     *
     * @return
     */
    CarEngine createCarEngine();

    /**
     * 生产轮胎
     *
     * @return
     */
    CarTire createCarTire();
}


/**
 * 汽车发动机
 */
interface CarEngine {
    void engine();
}

/**
 * 汽车轮胎
 */
interface CarTire {
    void tire();
}

class NormalTire implements CarTire {
    @Override
    public void tire() {
        System.out.println("普通轮胎");
    }
}

class SuvTire implements CarTire {
    @Override
    public void tire() {
        System.out.println("SUV轮胎");
    }
}

class DomesticEngine implements CarEngine {
    @Override
    public void engine() {
        System.out.println("国产发动机");
    }
}

class ImportEngine implements CarEngine {

    @Override
    public void engine() {
        System.out.println("进口发动机");
    }
}

class Q3Factory implements CarFactory {

    public Q3Factory() {
        System.out.println("开始生产Q3汽车");
    }

    @Override
    public CarEngine createCarEngine() {
        return new DomesticEngine();
    }

    @Override
    public CarTire createCarTire() {
        return new NormalTire();
    }
}

class Q5Factory implements CarFactory {

    public Q5Factory() {
        System.out.println("开始生产Q5汽车");
    }

    @Override
    public CarEngine createCarEngine() {
        return new ImportEngine();
    }

    @Override
    public CarTire createCarTire() {
        return new SuvTire();
    }
}